﻿using System;
using System.Collections.Generic;
using FastReflectionLib;
using System.Reflection;

namespace Layers.History
{
    public class FieldMeta:IPropertyAccessor
    {
        private MemberInfo _mi;
        private IFieldAccessor _accessor;
        private Type _type;

        public FieldMeta(MemberInfo mi)
        {
            _mi = mi;
            if (_mi is FieldInfo)
            {
                _accessor = FastReflectionCaches.FieldAccessorCache.Get(_mi as FieldInfo);
                _type = (mi as FieldInfo).FieldType;
            }
            else if (_mi is PropertyInfo)
            {
                _accessor = FastReflectionCaches.PropertyAccessorCache.Get(_mi as PropertyInfo);
                _type = (mi as PropertyInfo).PropertyType;
            }
        }

        public Type Type { get { return _type; } }
        public string Name { get { return _mi.Name; } }

        public object GetValue(object obj)
        {
            //return _accessor.GetValue(obj);
            if (_mi is FieldInfo)
                return (_mi as FieldInfo).GetValue(obj);
            return _accessor.GetValue(obj);
        }

        public void SetValue(object obj, object value)
        {
            if (_mi is FieldInfo)
                (_mi as FieldInfo).SetValue(obj,value);
            else
                (_accessor as IPropertyAccessor).SetValue(obj, value);
        }
    }

    public class ClassMeta
    {
        private Type _type;

        public ClassMeta(Type type)
        {
            _type = type;

            foreach(MemberInfo mi in type.GetFields())
            {
                _map.Add(mi.Name, new FieldMeta(mi));
            }

            foreach (MemberInfo mi in type.GetProperties())
            {
                _map.Add(mi.Name, new FieldMeta(mi));
            }

        }

        public Type Type { get { return _type;} }

        public IList<IColumn> ToColumnList<T>()  where T:Column,new()
        {
            IList<IColumn> columns = Factory.NewList<IColumn>();
            foreach (FieldMeta fm in _map.Values)
            {
                Column col = new T();
                col.Meta = fm;

                columns.Add(col);
            }
            return columns;
        }

        public IEnumerable<FieldMeta> Members
        {
            get {
                foreach (FieldMeta mi in _map.Values)
                    yield return mi;
            }
        }

        public IEnumerable<FieldMeta> FilterMembers(Predicate<FieldMeta> p)
        {
                foreach(FieldMeta mi in _map.Values)
                    if(p(mi))
                        yield return mi;

        }

        private IDictionary<string, FieldMeta> _map = Factory.NewDictionary<string, FieldMeta>();
    }

    public interface IColumn
    {
        Type Type { get; }
        string Name { get; }
        IPropertyAccessor Accessor { get; }
        DataNode NewNode();
    }

    public class Column : IColumn
    {
        public FieldMeta Meta { get; set; }

        public Type Type { get { return Meta.Type; } }
        public string Name { get { return Meta.Name; } }

        public object Converter { get; set; }

        public IPropertyAccessor Accessor { get { return Meta; } }

        public Column(FieldMeta meta)
        {
            Meta = meta;
        }

        public Column()
        {
        }

        public DataNode NewNode()
        {
            DiffHuffmanNode node = new DiffHuffmanNode();
            node.Type = Type;
            return node;
        }
    }

    

}